iT邦幫忙

2024 iThome 鐵人賽

DAY 10
1
Software Development

Rust 學得動嗎系列 第 10

[Day 10] Rust 的進階特性:不安全程式碼、進階特徵與型別系統

  • 分享至 

  • xImage
  •  

今天,我們將學習 Rust 的一些進階特性,包括不安全 Rust、進階特徵和型別系統的更多細節。

1. 不安全 Rust(Unsafe Rust)

不安全 Rust 允許我們執行一些在安全 Rust 中被禁止的操作。但這也意味著程式設計師需要自行確保記憶體安全。

不安全的超能力

在不安全區塊中,我們可以:

  1. 解引用原始指標
  2. 呼叫不安全函式或方法
  3. 存取或修改可變靜態變數
  4. 實作不安全特徵

範例:使用原始指標

fn main() {
    let mut num = 5;

    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;

    unsafe {
        println!("r1 指向的值:{}", *r1);
        *r2 += 1;
        println!("r2 修改後的值:{}", *r2);
    }
}

https://ithelp.ithome.com.tw/upload/images/20240924/20140358wl4bydQ8aZ.png

2. 進階特徵(Advanced Traits)

關聯型別(Associated Types)

關聯型別 允許我們在特徵定義中指定佔位型別。

trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}

struct Counter {
    count: u32,
}

impl Iterator for Counter {
    type Item = u32;
    
    fn next(&mut self) -> Option<Self::Item> {
        self.count += 1;
        if self.count < 6 {
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let mut counter = Counter { count: 0 };
    println!("{:?}", counter.next());
    println!("{:?}", counter.next());
}

https://ithelp.ithome.com.tw/upload/images/20240924/20140358PP2mJgvumV.png

預設型別參數(Default Type Parameters)

我們可以為泛型型別參數指定預設型別。

use std::ops::Add;

#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

fn main() {
    assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
               Point { x: 3, y: 3 });
}

https://ithelp.ithome.com.tw/upload/images/20240924/20140358CjHxp1AF1j.png

3. 進階型別系統(Advanced Type System)

新型別模式(Newtype Pattern)

新型別模式允許我們創建一個封裝了另一個型別的新型別。

struct Kilometers(f64);

impl Kilometers {
    fn to_miles(&self) -> f64 {
        self.0 * 0.621371
    }
}

fn main() {
    let distance = Kilometers(100.0);
    println!("{}公里等於{}英里", distance.0, distance.to_miles());
}

https://ithelp.ithome.com.tw/upload/images/20240924/20140358i9cVz5RpBE.png

型別別名(Type Aliases)

型別別名讓我們可以為已存在的型別建立另一個名稱。

type Thunk = Box<dyn Fn() + Send + 'static>;

let f: Thunk = Box::new(|| println!("嗨"));

fn takes_long_type(f: Thunk) {
    // --省略--
}

fn returns_long_type() -> Thunk {
    // --省略--
    Box::new(|| ())
}

Never 型別(!

Never 型別!)代表一個永不返回的計算。

fn bar() -> ! {
    panic!("這個函式永不返回!");
}

fn main() {
    let guess: u32 = match "3".parse() {
        Ok(num) => num,
        Err(_) => {
            println!("無法解析數字");
            return; // 這裡的 return 的型別是 `!`
        }
    };
    println!("猜測的數字是:{}", guess);
}

https://ithelp.ithome.com.tw/upload/images/20240924/20140358VGyBuTQH2a.png

實際應用範例:安全封裝不安全程式碼

讓我們來實現一個簡單的記憶體池,它使用不安全的 Rust 來管理記憶體,但對外提供安全的介面。

use std::alloc::{alloc, dealloc, Layout};
use std::marker::PhantomData;
use std::mem;
use std::ptr::NonNull;

struct MemoryPool<T> {
    data: NonNull<T>,
    capacity: usize,
    _marker: PhantomData<T>,
}

impl<T> MemoryPool<T> {
    pub fn new(capacity: usize) -> Self {
        let layout = Layout::array::<T>(capacity).unwrap();
        let data = unsafe { NonNull::new(alloc(layout) as *mut T).unwrap() };
        MemoryPool { data, capacity, _marker: PhantomData }
    }

    pub fn allocate(&self, value: T) -> Option<NonNull<T>> {
        if self.capacity == 0 {
            return None;
        }

        unsafe {
            let ptr = self.data.as_ptr().add(self.capacity - 1);
            ptr.write(value);
            Some(NonNull::new_unchecked(ptr))
        }
    }
}

impl<T> Drop for MemoryPool<T> {
    fn drop(&mut self) {
        let layout = Layout::array::<T>(self.capacity).unwrap();
        unsafe {
            dealloc(self.data.as_ptr() as *mut u8, layout);
        }
    }
}

fn main() {
    let pool = MemoryPool::<i32>::new(5);
    let ptr = pool.allocate(42).unwrap();
    unsafe {
        println!("分配的值:{}", *ptr.as_ptr());
    }
}

https://ithelp.ithome.com.tw/upload/images/20240924/201403589bzdeiv8xg.png

明天,我們將學習 Rust 的模組系統、套件管理和測試,對組織更大型的 Rust 專案並確保程式碼品質有很大的幫助。


上一篇
[Day 9] Rust 的智慧指標與內部可變性:靈活管理記憶體和共享資料
下一篇
[Day 11] Rust 的模組系統、套件管理與測試
系列文
Rust 學得動嗎13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言